When writing code during the development of software applications, developers commonly spend a significant amount of time “debugging” the code to find runtime and other source code errors. In doing so, developers may take several approaches to reproduce and localize a source code bug, such as observing behavior of a program based on different inputs, inserting debugging code (e.g., to print variable values, to track branches of execution, etc.), temporarily removing code portions, etc. Tracking down runtime errors to pinpoint code bugs can occupy a significant portion of application development time.
Many types of debugging applications (“debuggers”) have been developed in order to assist developers with the code debugging process. These tools offer developers the ability to trace, visualize, and alter the execution of computer code. For example, debuggers may visualize the execution of code instructions, may present code variable values at various times during code execution, may enable developers to alter code execution paths, and/or may enable developers to set “breakpoints” and/or “watchpoints” on code elements of interest (which, when reached during execution, causes execution of the code to be suspended), among other things.
An emerging form of debugging applications enable “time travel,” “reverse,” or “historic” debugging. With “time travel” debugging, execution of a program (e.g., executable entities such as threads) is recorded/traced by a trace application into one or more trace files. These trace file(s) can then be used to replay execution of the program later, for both forward and backward analysis. For example, “time travel” debuggers can enable a developer to set forward breakpoints/watchpoints (like conventional debuggers) as well as reverse breakpoints/watchpoints.
In order to facilitate recording, existing “time travel” debuggers force applications that are being recorded to execute as if they were single-threaded and executing at one single-threaded processor core, regardless of whether or not the application is capable of being executed multi-threaded. This done so that the existing debuggers are able to record a complete record of execution of the application, including recording an exhaustive record of everything that happens during execution of the application, including all of the processor instructions executed, all of the memory reads and writes, etc.
Furthermore, existing “time travel” debuggers require traces be replayed on processing hardware that is identical to the hardware on which the trace was recorded (e.g., identical processor models). One reason for this is that different models of processors implementing the same instruction set architecture (ISA)—even those manufactured by the same manufacturer—may exhibit different behaviors when executing the same instruction. Thus, if a trace is being replayed on a different model of processor than it was recorded on, these different behaviors could result in an inability to re-execute the traced instructions identically to how they executed at replay time.